<template>
  <div class="table-box">
    <div
      class="table-headline"
      v-if="!hideHeadline">
      <slot name="title">查询结果</slot>
      <div class="headline-actions">
        <slot
          name="headAction"
          v-bind="{ selection, table: $refs.table, reload, refresh }" />
      </div>
    </div>
    <transition name="expand">
      <div
        v-if="selection.length > 0 && !hideSelection"
        class="table-select">
        <span class="select-text">已选择 {{ selection.length }} 项</span>
        <el-button
          link
          type="primary"
          @click="$refs.table.clearSelection()">
          取消选择
        </el-button>

        <div class="select-action">
          <slot
            v-bind="{ selection, table: $refs.table, reload, refresh }"
            name="selectAction" />
        </div>
      </div>
    </transition>
    <el-table
      ref="table"
      v-loading="!!loading"
      class="table-main"
      size="large"
      :border="border"
      :data="data"
      :span-method="tableSpanMethod"
      row-key="id"
      :max-height="heightAuto ? '—' : tableHeight"
      @selection-change="(selection = $event), $emit('select', $event)">
      <el-table-column
        v-if="!!selectable"
        type="selection"
        class-name="col-checkbox"
        width="50"
        :selectable="typeof selectable === 'function' ? selectable : () => true"
        :reserve-selection="reserveSelection ? reserveSelection : false" />

      <el-table-column
        v-if="showIndex"
        label="序号"
        type="index"
        width="60"
        fixed="left" />
      <el-table-column
        v-for="col in cols"
        :key="col.key"
        :type="col.type"
        :prop="col.prop"
        :min-width="100"
        v-bind="col"
        :fixed="col.label == '操作' || col.type == 'expand' ? 'right' : false">
        <template #default="{ row, column, $index }">
          <slot
            v-bind="{ row, column, index: $index, selection, table: $refs.table, reload, refresh }"
            :name="col.key">
            <div v-if="row[col.key] && row[col.key].length && row[col.key].length > 30">
              <el-popover
                placement="top-start"
                :width="300"
                trigger="hover"
                :content="row[col.key]">
                <template #reference>
                  {{ row[col.key].slice(0, 30) + '...' }}
                </template>
              </el-popover>
            </div>
            <div v-else>{{ row[col.key] || row[col.key] == 0 ? row[col.key] : '-' }}</div>
          </slot>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      v-if="!hidePaging"
      v-model:current-page="page.current"
      v-model:page-size="page.size"
      :page-sizes="pageSizes"
      :pager-count="5"
      :total="page.total"
      class="table-pagination"
      layout="total,prev,pager,next,sizes,jumper"
      @current-change="reload"
      @size-change="reload" />
  </div>
</template>

<script>
export default {
  name: 'TableBox',
  props: {
    xhr: Function,
    cols: Array,
    heightAuto: [Boolean],
    selectable: [Function, Boolean],
    tableSpanMethod: [Function],
    hideHeadline: {
      type: Boolean,
      default: false,
    },
    border: {
      type: Boolean,
      default: false,
    },
    hideSelection: Boolean,
    hidePaging: Boolean,
    showIndex: Boolean,
    reserveSelection: Boolean,
    expand: Boolean,
  },
  data() {
    const sizes = [10, 20, 50];
    return {
      selection: [],
      data: [],
      pageSizes: sizes,
      page: {
        current: 1,
        size: sizes[0],
        total: 0,
      },
      loading: false,
      tableHeight: 480,
    };
  },
  created() {
    this.reload();
  },
  mounted() {
    this.changeSize();
  },
  methods: {
    async reload() {
      if (!this.reserveSelection) {
        this.$refs.table?.clearSelection();
      }
      this.loading = true;
      try {
        const { data = [], totalCount = 0 } = await this.xhr({
          current: this.page.current,
          size: this.hidePaging ? 99999999 : this.page.size,
        });
        this.loading = false;
        if (data) {
          this.data = data;
          this.page.total = totalCount;
        }
      } finally {
        this.loading = false;
      }
    },
    refresh() {
      this.page.current = 1;
      this.reload();
    },
    toggleSelection(rows, beforeMatchKey, afterMatchKey, selected = true) {
      this.$nextTick(() => {
        const renderTimer = setTimeout(() => {
          if (rows && this.data.length != 0) {
            this.data.forEach(row => {
              rows.forEach(item => {
                if (row[afterMatchKey] == (item[beforeMatchKey] || item[afterMatchKey])) {
                  this.$refs.table.toggleRowSelection(row, selected);
                }
              });
            });
          } else {
            this.$refs.table.clearSelection();
          }
          clearTimeout(renderTimer);
        }, 0);
      });
    },
    toggleAllExpansion() {
      this.$nextTick(() => {
        const timer = setTimeout(() => {
          clearTimeout(timer);
          this.data.forEach(row => {
            this.$refs.table.toggleRowExpansion(row, false);
          });
        }, 500);
      });
    },
    setData({ data, totalCount }) {
      this.$refs.table?.clearSelection();
      this.loading = true;
      const timer = setTimeout(() => {
        this.loading = false;
        clearTimeout(timer);
        if (data) {
          this.data = data;
          this.page.total = totalCount;
        }
      }, 1500);
    },
    changeSize() {
      this.$nextTick(() => {
        const searchBoxEl = document.querySelector('#dp-search-box');
        if (!searchBoxEl) return;
        if (
          document.documentElement.clientHeight > 0 &&
          document.documentElement.clientHeight < 560
        ) {
          this.tableHeight = 480;
        } else if (
          document.documentElement.clientHeight > 560 &&
          document.documentElement.clientHeight < 980
        ) {
          this.tableHeight = 480;
        } else {
          this.tableHeight = 560;
        }
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.table-box {
  @include shadow;
  padding: 24px 24px 8px;
  background-color: #fff;
  margin-top: 16px;
  flex: 1;
  display: flex;
  flex-direction: column;
  > * {
    flex-shrink: 0;
    margin-bottom: 16px;
    :last-child {
      margin-bottom: 0;
    }
  }

  .table-headline {
    display: flex;
    flex-flow: row wrap;
    align-items: center;
  }
  .headline-actions {
    margin-left: auto;
    justify-self: flex-end;
  }

  .table-wrapper {
    flex: 1;
    min-height: 300px;
  }

  .table-select {
    padding: 12px 24px;
    box-sizing: border-box;
    max-height: 48px;
    overflow: hidden;
    display: flex;
    flex-flow: row wrap;
    background-color: rgba(2, 170, 94, 0.04);
    border: 1px solid rgba(57, 164, 116, 0.47);

    .select-text {
      color: #555;
      font-size: 14px;
      display: inline-block;
      margin-right: 8px;
    }

    .select-action {
      margin-left: auto;
      justify-self: flex-end;
    }
  }

  .table-main {
    :deep(thead th) {
      background-color: #fafafa;
    }
    :deep(.col-checkbox) {
      text-align: center;
      .cell {
        padding: 0 8px;
      }
    }
  }

  .table-pagination {
    justify-content: flex-end;
    :deep(.el-pagination) {
      .el-pagination__sizes {
        margin-right: 0;

        .el-input {
          width: 88px;
        }
        .el-input__wrapper {
          padding: 0 4px;
        }
        .el-select__caret.el-icon {
          margin-left: 4px;
        }
      }

      .el-pagination__jump {
        .el-input {
          width: 48px;
          min-width: unset;
        }
      }

      .btn-prev,
      .btn-next,
      .el-pager > li {
        border: 1px solid #dadada;
        border-radius: 2px;
        margin: 0 8px;
        &.is-active {
          border-color: currentColor;
        }
      }
    }
  }
}
</style>
